package com.lifeverse.service;

import com.lifeverse.entity.enums.AlertStatus;
import com.lifeverse.entity.enums.HealthStatus;
import com.lifeverse.repository.HealthCheckRepository;
import com.lifeverse.repository.ServiceDiscoveryRepository;
import com.lifeverse.repository.SystemAlertRepository;
import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.Gauge;
import io.micrometer.core.instrument.MeterRegistry;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.concurrent.atomic.AtomicLong;

/**
 * 指标收集服务
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class MetricsCollectionService {

    private final SystemAlertRepository alertRepository;
    private final HealthCheckRepository healthCheckRepository;
    private final ServiceDiscoveryRepository serviceDiscoveryRepository;
    private final MeterRegistry meterRegistry;

    // 原子计数器用于存储指标值
    private final AtomicLong activeAlertsCount = new AtomicLong(0);
    private final AtomicLong healthyServicesCount = new AtomicLong(0);
    private final AtomicLong unhealthyServicesCount = new AtomicLong(0);
    private final AtomicLong availableServicesCount = new AtomicLong(0);

    /**
     * 初始化指标收集
     */
    public void initializeMetrics() {
        // 注册动态指标
        Gauge.builder("lifeverse_alerts_active_count")
                .description("Number of active alerts")
                .register(meterRegistry, activeAlertsCount, AtomicLong::get);

        Gauge.builder("lifeverse_services_healthy_count")
                .description("Number of healthy services")
                .register(meterRegistry, healthyServicesCount, AtomicLong::get);

        Gauge.builder("lifeverse_services_unhealthy_count")
                .description("Number of unhealthy services")
                .register(meterRegistry, unhealthyServicesCount, AtomicLong::get);

        Gauge.builder("lifeverse_services_available_count")
                .description("Number of available services")
                .register(meterRegistry, availableServicesCount, AtomicLong::get);

        log.info("指标收集服务初始化完成");
    }

    /**
     * 定时收集系统指标
     */
    @Scheduled(fixedRate = 30000) // 每30秒收集一次
    public void collectSystemMetrics() {
        try {
            // 收集告警指标
            collectAlertMetrics();
            
            // 收集健康检查指标
            collectHealthMetrics();
            
            // 收集服务发现指标
            collectServiceDiscoveryMetrics();
            
            // 收集系统资源指标
            collectSystemResourceMetrics();
            
            log.debug("系统指标收集完成");
            
        } catch (Exception e) {
            log.error("收集系统指标时发生错误", e);
        }
    }

    /**
     * 收集告警相关指标
     */
    private void collectAlertMetrics() {
        // 活跃告警数量
        long activeAlerts = alertRepository.findByStatus(AlertStatus.ACTIVE).size();
        activeAlertsCount.set(activeAlerts);

        // 按严重程度统计告警
        alertRepository.countBySeverity().forEach(row -> {
            String severity = ((com.lifeverse.entity.enums.AlertSeverity) row[0]).name().toLowerCase();
            Long count = (Long) row[1];
            
            Gauge.builder("lifeverse_alerts_by_severity")
                    .description("Number of alerts by severity")
                    .tag("severity", severity)
                    .register(meterRegistry, count, Long::doubleValue);
        });

        // 最近24小时告警趋势
        LocalDateTime since = LocalDateTime.now().minusHours(24);
        long recentAlerts = alertRepository.countBySourceSince(since).stream()
                .mapToLong(row -> (Long) row[1])
                .sum();
        
        Gauge.builder("lifeverse_alerts_recent_24h")
                .description("Number of alerts in last 24 hours")
                .register(meterRegistry, recentAlerts, Long::doubleValue);
    }

    /**
     * 收集健康检查指标
     */
    private void collectHealthMetrics() {
        // 按状态统计健康检查
        long healthy = 0;
        long unhealthy = 0;
        
        healthCheckRepository.countByStatus().forEach(row -> {
            HealthStatus status = (HealthStatus) row[0];
            Long count = (Long) row[1];
            
            if (status.isNormal()) {
                healthy += count;
            } else {
                unhealthy += count;
            }
            
            Gauge.builder("lifeverse_health_checks_by_status")
                    .description("Number of health checks by status")
                    .tag("status", status.name().toLowerCase())
                    .register(meterRegistry, count, Long::doubleValue);
        });
        
        healthyServicesCount.set(healthy);
        unhealthyServicesCount.set(unhealthy);

        // 平均响应时间
        LocalDateTime since = LocalDateTime.now().minusHours(1);
        healthCheckRepository.getAverageResponseTimeByService(since).forEach(row -> {
            String serviceName = (String) row[0];
            Double avgResponseTime = (Double) row[1];
            
            Gauge.builder("lifeverse_health_check_avg_response_time")
                    .description("Average health check response time by service")
                    .tag("service", serviceName)
                    .register(meterRegistry, avgResponseTime, Double::doubleValue);
        });

        // 服务可用性
        healthCheckRepository.getServiceAvailability(since).forEach(row -> {
            String serviceName = (String) row[0];
            Double availability = (Double) row[1];
            
            Gauge.builder("lifeverse_service_availability")
                    .description("Service availability percentage")
                    .tag("service", serviceName)
                    .register(meterRegistry, availability, Double::doubleValue);
        });
    }

    /**
     * 收集服务发现指标
     */
    private void collectServiceDiscoveryMetrics() {
        // 可用服务数量
        LocalDateTime heartbeatThreshold = LocalDateTime.now().minusSeconds(90);
        long available = serviceDiscoveryRepository.findAvailableServices(heartbeatThreshold).size();
        availableServicesCount.set(available);

        // 按状态统计服务
        serviceDiscoveryRepository.countByStatus().forEach(row -> {
            com.lifeverse.entity.enums.HealthStatus status = (com.lifeverse.entity.enums.HealthStatus) row[0];
            Long count = (Long) row[1];
            
            Gauge.builder("lifeverse_services_by_status")
                    .description("Number of services by status")
                    .tag("status", status.name().toLowerCase())
                    .register(meterRegistry, count, Long::doubleValue);
        });

        // 按环境统计服务
        serviceDiscoveryRepository.countByEnvironment().forEach(row -> {
            String environment = (String) row[0];
            Long count = (Long) row[1];
            
            if (environment != null) {
                Gauge.builder("lifeverse_services_by_environment")
                        .description("Number of services by environment")
                        .tag("environment", environment)
                        .register(meterRegistry, count, Long::doubleValue);
            }
        });

        // 按服务名统计实例数
        serviceDiscoveryRepository.countInstancesByService().forEach(row -> {
            String serviceName = (String) row[0];
            Long count = (Long) row[1];
            
            Gauge.builder("lifeverse_service_instances")
                    .description("Number of instances per service")
                    .tag("service", serviceName)
                    .register(meterRegistry, count, Long::doubleValue);
        });
    }

    /**
     * 收集系统资源指标
     */
    private void collectSystemResourceMetrics() {
        // JVM内存使用情况
        Runtime runtime = Runtime.getRuntime();
        long totalMemory = runtime.totalMemory();
        long freeMemory = runtime.freeMemory();
        long usedMemory = totalMemory - freeMemory;
        long maxMemory = runtime.maxMemory();

        Gauge.builder("lifeverse_jvm_memory_used")
                .description("JVM used memory in bytes")
                .register(meterRegistry, usedMemory, Long::doubleValue);

        Gauge.builder("lifeverse_jvm_memory_total")
                .description("JVM total memory in bytes")
                .register(meterRegistry, totalMemory, Long::doubleValue);

        Gauge.builder("lifeverse_jvm_memory_max")
                .description("JVM max memory in bytes")
                .register(meterRegistry, maxMemory, Long::doubleValue);

        double memoryUsagePercent = (double) usedMemory / maxMemory * 100;
        Gauge.builder("lifeverse_jvm_memory_usage_percent")
                .description("JVM memory usage percentage")
                .register(meterRegistry, memoryUsagePercent, Double::doubleValue);

        // 线程数
        int threadCount = Thread.activeCount();
        Gauge.builder("lifeverse_jvm_threads")
                .description("Number of active JVM threads")
                .register(meterRegistry, threadCount, Integer::doubleValue);

        // 系统负载
        double systemLoad = java.lang.management.ManagementFactory.getOperatingSystemMXBean().getSystemLoadAverage();
        if (systemLoad >= 0) {
            Gauge.builder("lifeverse_system_load")
                    .description("System load average")
                    .register(meterRegistry, systemLoad, Double::doubleValue);
        }
    }

    /**
     * 记录告警创建事件
     */
    public void recordAlertCreated(String severity, String source) {
        Counter.builder("lifeverse_alerts_created_total")
                .description("Total number of alerts created")
                .tag("severity", severity.toLowerCase())
                .tag("source", source)
                .register(meterRegistry)
                .increment();
    }

    /**
     * 记录告警解决事件
     */
    public void recordAlertResolved(String severity, String source, long durationSeconds) {
        Counter.builder("lifeverse_alerts_resolved_total")
                .description("Total number of alerts resolved")
                .tag("severity", severity.toLowerCase())
                .tag("source", source)
                .register(meterRegistry)
                .increment();

        Gauge.builder("lifeverse_alert_resolution_time")
                .description("Alert resolution time in seconds")
                .tag("severity", severity.toLowerCase())
                .tag("source", source)
                .register(meterRegistry, durationSeconds, Long::doubleValue);
    }

    /**
     * 记录健康检查执行
     */
    public void recordHealthCheckExecution(String serviceName, String status, long responseTimeMs) {
        Counter.builder("lifeverse_health_checks_executed_total")
                .description("Total number of health checks executed")
                .tag("service", serviceName)
                .tag("status", status.toLowerCase())
                .register(meterRegistry)
                .increment();

        Gauge.builder("lifeverse_health_check_response_time")
                .description("Health check response time in milliseconds")
                .tag("service", serviceName)
                .register(meterRegistry, responseTimeMs, Long::doubleValue);
    }

    /**
     * 记录服务注册事件
     */
    public void recordServiceRegistration(String serviceName, String environment) {
        Counter.builder("lifeverse_services_registered_total")
                .description("Total number of services registered")
                .tag("service", serviceName)
                .tag("environment", environment != null ? environment : "unknown")
                .register(meterRegistry)
                .increment();
    }

    /**
     * 记录服务注销事件
     */
    public void recordServiceDeregistration(String serviceName, String environment) {
        Counter.builder("lifeverse_services_deregistered_total")
                .description("Total number of services deregistered")
                .tag("service", serviceName)
                .tag("environment", environment != null ? environment : "unknown")
                .register(meterRegistry)
                .increment();
    }
}